package com.csap.framework.oauth2.server.service.impl;

import cn.dev33.satoken.LoginUtil;
import cn.dev33.satoken.SaManager;
import com.csap.framework.extension.CsapException;
import com.csap.framework.oauth2.IUserDataCache;
import com.csap.framework.oauth2.request.RolesRequest;
import com.csap.framework.oauth2.request.RolesResponse;
import com.csap.framework.oauth2.server.entity.RolesEntity;
import com.csap.framework.oauth2.server.model.RolesModel;
import com.csap.framework.oauth2.server.mybatis.RolesMapper;
import com.csap.framework.oauth2.server.service.RolesService;
import com.csap.framework.oauth2.server.service.UserRolesService;
import com.csap.framework.redis.RedisUtil;
import com.csap.framework.util.Assert;
import com.csap.framework.util.CollectionsUtil;
import com.csap.framework.util.StringUtil;
import com.csap.framework.util.bean.BeanCopierUtil;
import com.csap.framework.util.exception.ExceptionUtils;
import com.csap.mybatisplus.extension.service.impl.BaseCsapServiceImpl;
import com.csap.mybatisplus.page.Page;
import com.google.common.collect.Lists;
import lombok.Getter;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色
 * </p>
 *
 * @author yangchengfu
 * @dateTime 2021-07-25 23:51:30
 */
@Service
public class RolesServiceImpl extends BaseCsapServiceImpl<RolesMapper, RolesEntity, RolesModel, Long> implements RolesService, IUserDataCache {
    @Resource
    @Getter
    private RedisUtil redisUtil;
    @Resource
    private UserRolesService userRolesService;

    @Override
    public Long insertRole(RolesModel t) {
        Assert.notEmpty(t.getName(), "角色名称不能为空");
        Assert.notNull(t.getType(), "类型不能为空");
        Assert.notNull(t.getTypeId(), "类型ID不能为空");
        clearRolePremissions(t.getRoleId());
        saveOrUpdate(t);
        return t.getRoleId();
    }

    @Override
    public List<String> findDescrByIds(List<Long> idList) {
        if (CollectionsUtil.isEmpty(idList)) {
            return Collections.emptyList();
        }
        return lambdaQuery().select(RolesEntity::getDescr)
                .in(RolesEntity::getRoleId, idList)
                .eq(RolesEntity::getDefaults, 0)
                .listOptional()
                .orElse(Collections.emptyList())
                .stream()
                .map(RolesEntity::getDescr)
                .collect(Collectors.toList());
    }

    @Override
    public Map<Long, RolesResponse> findMapByIds(String ids) {
        if (StringUtil.isEmpty(ids)) {
            return Collections.emptyMap();
        }
        return lambdaQuery()
                .select()
                .in(RolesEntity::getRoleId, Lists.newArrayList(ids.split(",")))
                .eq(RolesEntity::getDefaults, 0)
                .listOptional()
                .orElse(Collections.emptyList())
                .stream()
                .map(i -> BeanCopierUtil.copy(i, RolesResponse.class))
                .collect(Collectors.toMap(RolesResponse::getRoleId, i -> i));
    }

    @Override
    public boolean update(RolesModel t) {
        Assert.notNull(t.getRoleId(), "角色ID不能为空");
        clearRolePremissions(t.getRoleId());
        return super.update(t);
    }

    @Override
    public boolean delete(Long aLong) {
        if (userRolesService.containsRole(aLong, null, null)) {
            throw ExceptionUtils.mpe("角色已有用户绑定，禁止删除");
        }
        validateDefault(aLong);
        clearRolePremissions(aLong);
        return super.delete(aLong);
    }

    private void validateDefault(Long id) {
        findById(id).isNullThrow(() -> new CsapException("角色不存在"))
                .isNotNullConditionThrow(i -> i.getDefaults().equals(1) || !i.getAvailableDel(), () -> new CsapException("默认角色禁止删除"));
    }

    @Override
    public Set<String> getRolePremissions(Set<String> roleId) {
        if (Objects.isNull(roleId)) {
            return Collections.emptySet();
        }
        return getRolePermissions(roleId, key -> {
            Map<String, Object> permissions = getRolePermissionsMap(roleId);
            redisUtil.hmset(key, permissions, SaManager.getConfig().getCache().getPermissionsTime());
            return permissions.values().stream().map(o -> (Set<String>) o).flatMap(Collection::stream).collect(Collectors.toSet());
        });

    }

    @Override
    public List<String> getRole(Set<String> roleId) {
        if (CollectionsUtil.isEmpty(roleId)) {
            return Collections.emptyList();
        }
        return getRoleList(roleId, key -> {
            Map<String, Object> role = getRoleMap(roleId);
            redisUtil.hmset(key, role, SaManager.getConfig().getCache().getPermissionsTime());
            return role.values().stream().map(o -> (String) o).collect(Collectors.toList());
        });
    }


    @Override
    public Page<RolesResponse> page(RolesRequest request, Page<RolesEntity> page) {
        return lambdaQuery()
                .select()
                .eq(RolesEntity::getName, request.getName())
                .eq(RolesEntity::getDefaults, request.getDefaults())
                .eq(RolesEntity::getType, request.getType())
                .eq(RolesEntity::getTypeId, request.getTypeId())
                .likeRight(RolesEntity::getDescr, request.getDescr())
                .in(RolesEntity::getRoleId, request.getIncludes())
                .eq(RolesEntity::getDeptId, request.getDeptId())
                .page(page)
                .convertPage(RolesResponse.class);
    }
}
